home *** CD-ROM | disk | FTP | other *** search
- DINAMIK YER ACMA
-
- Dinamik yer acma, ilk karsilastiginizda korkutucu bir tanimdir, fakat
- aslinda o kadar zor degildir. Su ana kadar kullandigimiz tum degiskenler,
- statik degiskenler idiler. Yani, derleyici tarafindan, derleme yada link
- etabinda kendilerine yer ayrilmisti. (Aslinda bazilari "otomatik"
- degiskenler olduklarindan, derleyici tarafindan dinamik olarak yer
- ayrilmisti, fakat bu bize gorunmuyordu). Dinamik degiskenler, program
- yuklendiginde var olmayan, fakat gerektiginde kendilerine hafizada yer
- tahsis edilen degiskenlerdir. Bu metod ile, diledigimiz kadar degiskeni
- tanimlamak, kullanmak, ve baska degiskenlerin o sahayi kullanmasi icin,
- o sahayi tekrar serbest birakabiliriz.
-
- DINLIST.C:
- ================================================================
- main()
- {
- struct hayvan {
- char ismi[25];
- char cinsi[25];
- int yasi;
- } *evcil1, *evcil2, *evcil3;
-
- evcil1 = (struct hayvan *)malloc(sizeof(struct hayvan));
- strcpy(evcil1->ismi,"General");
- strcpy(evcil1->cinsi,"Karisik Birsey");
- evcil1->yasi = 1;
-
- evcil2 = evcil1; /* evcil2 simdi yukaridaki veri
- yapisina karsilik geliyor */
-
- evcil1 = (struct hayvan *)malloc(sizeof(struct hayvan));
- strcpy(evcil1->ismi,"Bobi");
- strcpy(evcil1->cinsi,"Labrador");
- evcil1->yasi = 3;
-
- evcil3 = (struct hayvan *)malloc(sizeof(struct hayvan));
- strcpy(evcil3->ismi,"Kristal");
- strcpy(evcil3->cinsi,"Alman Coban");
- evcil3->yasi = 4;
-
- /* Yukardaki bilgiyi yazalim */
-
- printf("%s, bir %sdir ve %d yasindadir.\n", evcil1->ismi,
- evcil1->cinsi, evcil1->yasi);
-
- printf("%s, bir %sdir ve %d yasindadir.\n", evcil2->ismi,
- evcil2->cinsi, evcil2->yasi);
-
- printf("%s, bir %sdir ve %d yasindadir.\n", evcil3->ismi,
- evcil3->cinsi, evcil3->yasi);
-
- evcil1 = evcil3; /* evcil1 simdi evcil3 un gosterdigi
- yapiyi gosteriyor */
-
- free(evcil3); /* bir structure'u siliyor */
- free(evcil2); /* bu da bir baska structure'u siliyor */
- /* free(evcil1); bu yapilamaz - niye? anlatacagim! */
- }
- ================================================================
-
- "hayvan" isimli bir structure tanimlama ile basliyoruz. Bu tanimladigimiz
- tip ile bir degisken tanimlamiyoruz, sadece 3 tane pointer tanimliyoruz.
- Bu programin devamina da bakarsaniz, hicbir yerde bir degisken tanimina
- rastlayamazsiniz. Guzel. Veriyi saklayabilecegimiz hicbir yer yok.
- Elimizdeki yegane sey, 3 tane pointers dir. Birseyler yapabilmek icin,
- degiskenler tanimlamamiz gerekli, o zaman dinamik olarak tanimlayalim.
-
- DINAMIK DEGISKEN TANIMLAMAK
-
- Programin ilk satiri, "evcil1" isimli pointer'a birsey atayarak 3
- degiskenden olusan bir dinamik yapi tanimliyor. Programin kalbi, satirin
- ortasinda gomulu bulunan "malloc" fonksiyonudur. Bu, baska bilgilere
- ihtiyaci olan "hafiza ayir" fonksiyonudur. "malloc" fonksiyonu, normalde,
- hafizanin "heap" denilen kesiminde, "n" karakter boyunda, ve karakter
- tipinde bir yer ayiracaktir. "n", fonksiyona gecirilen yegane
- parametredir. "n" hakkinda birazdan konusacagiz, fakat ilk once "heap":
-
- HEAP NEDIR?
-
- Her derleyicinin calisacak kodun boyu, kac degisken
- kullanilabilecegi, kaynak kodun boyu gibi sinirlari vardir. IBM-PC ve
- uyumlular icin bu sinir cogu derleyici icin 64K lik bir calisacak kod
- boyudur. (Calisacak koddan kastim, ismi EXE yada COM ile biten
- kutuklerdir.) Bunun sebebi, IBM-PC nin 64K lik segman boyuna sahip bir
- mikroisleyiciye sahip olmasindandir. Daha "uzakta" yer alan veriye ise,
- ozel erisme yontemleri gerektirmektedir. Programi kucuk ve verimli tutmak
- icin, bu yontemler kullanilmamakta, ve program, cogu programlar icin
- yeterli olan 64K lik bir sahaya sigmak zorunlulugundadir.
-
- Heap sahasi, bu 64K lik sahanin disinda bulunan ve programlarin veri ve
- degisken saklamak icin kullanilabilecekleri bir yerdir. Veriler ve
- degiskenler, sistem tarafindan "malloc" cagirilinca heap'e konur. Sistem,
- verinin nereye kondugunu takip eder. Istedigimizde, bir degiskeni tanimsiz
- yaparak, heap de bosluklar yaratiriz. Sistem bu bosluklara, yeni "malloc"
- tanimlari oldugunda baska veriler koyarak kullanir. Yani, heap'in yapisi
- son derece dinamiktir - surekli degisir..
-
- SEGMANLAR HAKKINDA
-
- Daha pahalli derleyiciler, kullanmak istediginiz hafiza tipini secmenizi
- saglarlar. Lattice yada Microsoft'un derleyicileri ile, program boyunun
- 64K nin altinda kalmasini, ve programin daha verimli calismasi ile
- programin 640K sinirinda kalmasi, daha uzun adresleme metodu ile daha az
- verimli calismasi arasinda bir secim yapabilirsiniz. Uzun adresleme,
- segmanlar arasi erisimi gerektireceginden, biraz daha yavas calisan
- programlara sebep olacaktir. Yavaslama, cogu programlar icin onemsiz
- olacaktir.
-
- Sayet bir programin kodu ve hafiza gereksinimi toplam 64K yi asmiyorsa, ve
- stack'i kullanmiyorsa, bir .COM kutugu haline getirilebilir. Bir .COM
- kutugu hafizanin bir kopyasi seklinde oldugu icin, cok hizli bir sekilde
- yuklenebilir. Halbuki .EXE tipindeki bir kutugun adreslerinin hafizada
- yeniden yerlestirilmesi gereklidir. Dolayisi ile ufak hafiza modeli, daha
- hizli yuklenen programlar yaratabilir. Bunun hakkinda endiselenmeyin,
- birkac programcinin endiselendigi ufak bir detaydir.
-
- Dinamik tanimlama ile, verileri "heap" e saklamak mumkundur. Tabii, lokal
- degiskenleri, ve indeks sayaclari tipindeki degisenleri heap de saklamak
- istemezsiniz - sadece buyuk dizileri ve structure'lari..
-
- Kucuk hafiza modelinde kalmaktan daha onemli birsey, bilgisayarin
- hafizasinin sinirlarinda kalmaktir. Sayet programiniz cok buyuk birkac
- saha tanimliyorsa, fakat bunlari ayni zamanda kullanmiyorsa, bir parcasini
- dinamik olarak tanimlayip, kullanip, silebilirsiniz. Sonra, ayni sahayi
- bir baska veri parcasi icin kullanabilirsiniz.
-
- "malloc" A GERI DONUS
-
- Umarim, "heap" hakkindaki parca, size "malloc" ile ne yaptigimizi
- gostermistir. Sadece, sisteme kendisine bir parca hafiza verilmesini talep
- edip, bu sahanin ilk elemanina (baslangicina) bir pointer dondurmektedir.
- Parantezler arasinda gerekli olan yegane parametre, istenilen blok'un
- boyudur. Bu programda, basinda tanimladigimiz structure'u saklayabilecek
- bir yere ihtiyacimiz vardir. "sizeof", yeni bir fonksiyondur, en azindan
- bize, ve parantezlerinin icindeki parametresinin boyunu byte cinsinden
- dondurmektedir. Yani, "hayvan" structure'unun boyunu byte olarak
- dondurmektedir. Bu deger "malloc" a dondurulur. Fonksiyonu cagirinca bize
- heap'de bir saha ayrilmis oluyor, ve "evcil1" bu sahanin baslangicini
- gosteriyor.
-
- CAST NEDIR?
-
- Hala, "malloc" fonksiyonun onunde, tuhaf gorunuslu bir birsey var. Buna
- "cast" denir. "malloc" fonksiyonu normalde, ayrilan sahanin baslangicini
- gosteren "char" tipli bir pointer dondurur. Cogu zaman, "char" tipli bir
- pointer istemeyiz. Biz bu ornekte, "hayvan" structure'unu gosterecek bir
- pointer istiyoruz, ve bu nedenle, derleyiciye bu tuhaf yapi ile bunu
- belirtiyoruz. Cast'i koymazsaniz, cogu derleyici, pointer'i dogru bir
- sekilde dondurecektir, size bir uyari mesaji verip, gayet iyi calisan bir
- program yaratacaktir. Iyi programlama teknigi, derleyicinin uyari
- mesajlari vermesine mani olmaktir.
-
-
- DINAMIK OLARAK TANIMLADIGIMIZ SAHAYI KULLANMAK
-
-
- Structure ve pointer konusu ile ilgili konusmamizi hatirlarsaniz, sayet
- bir structure'umuz ve onu gosteren bir pointer'imiz varsa, icindeki
- herhangi bir degiskene erisebiliriz. Denemek icin, programin bundan
- sonraki 3 satirinda, structure'a degerler atayacagiz. Bu komutlarin statik
- olarak tanimli atamalara benzedigini fark edeceksiniz.
-
- Bundan sonraki satirda, "evcil1" in degerini "evcil2" ye atiyoruz. Bunu
- yapmak, yeni bir veri yaratmiyor, sadece ayni yeri gosteren iki tane
- pointer'imiz oluyor. "evcil2", simdi yarattigimiz structure'u gosterdigi
- icin, "evcil1", birbaska dinamik tanimli structure yaratmakta
- kullanilabilir.
-
- o "evcil2" yi de yeni dinamik tanim icin kullanabilirdik.
-
- Sonunda, bir baska saha tanimlayip, "evcil3" u bunun baslangicina
- atiyoruz.
-
- DINAMIK TANIMLI SAHADAN KURTULMAK
-
- Birbaska yeni fonksiyon ise, "free" dir. Bu fonksiyon, ayirdigimiz hafiza
- parcasini tekrar sisteme iade etmekte kullanilir. Kullanimi icin, bloku
- gosteren bir pointer'i, parametre olarak gecirin.
-
- Dinamik tanimin bir baska ozelligini gostermek icin, bir baska sey daha
- yapiyoruz. "evcil1" in degeri, "evcil3" e ataniyor. Bunu yaparak, "evcil1"
- in tuttugu degeri kaybetmis oluyoruz - cunku artik "evcil3" un degerini
- tutmaktadir. Dolayisi ile, artik hicbir zaman kullanilamaz. Bu hafiza
- sahasi, bu noktadan sonra erisilemez, ve "ziyan" olmustur. Bu, bir
- programda normal olarak yapmayacaginiz birseydir - sadece dikkatinizi
- cekmek icin konulmustur.
-
- Ilk "free" fonksiyon cagirimi, "evcil1" ve "evcil3" un gosterdigi sahayi
- ortadan kaldirir, ikincisi de "evcil2" nin gosterdigi sahayi ortadan
- kaldirir. Dolayisi ile, daha once yarattigimiz verileri kaybetmis olduk.
- Heap'de bir parca daha bilgi vardir, fakat onun yerini gosteren bir
- pointer olmadigi icin, erisilemez. "evcil1" in sahasini tekrar "free"
- etmeye calismak, bir hata olacaktir, cunku zaten "evcil3" ile ayni yer
- ortadan kaldirilmistir. Fakat endiselenmeye luzum yoktur, cunku DOS a
- donunce, butun heap sahasi silinecektir.
-
- BAYAGI COK KONUSTUK
-
- Bu son program hakkinda nerdeyse 4 sayfa konustuk, fakat iyi harcanmis bir
- zaman idi bu. Sizin icin dinamik tanimlama hakkinda ogrenmediginiz hicbir
- seyin kalmadigini bilmek, sevindirici birsey olmali. Tabii ki, bu sahanin
- kullanimi hakkinda bircok sey orgenebilirsiniz, fakat dinamik tanimlama
- hakkinda daha fazla ogrenebileceginiz birsey yoktur.
-
- BIR POINTER DIZISI
-
- BUYUKDIN.C:
- ================================================================
-
- main()
- {
- struct hayvan {
- char ismi[25];
- char cinsi[25];
- int yasi;
- } *evcil[12], *point; /* bu, 13 tane pointer ve
- 0 degisken tanimliyor */
-
- int index;
-
- /* ilk once, dinamik sahayi ivir zivirla dolduralim. */
-
- for (index = 0;index < 12;index++) {
- evcil[index] = (struct hayvan *)malloc(sizeof(struct hayvan));
- strcpy(evcil[index]->ismi,"General");
- strcpy(evcil[index]->cinsi,"Karisik cins");
- evcil[index]->yasi = 4;
- }
-
- evcil[4]->yasi = 12; /* Bu atamalar, bazi sahalara */
- evcil[5]->yasi = 15; /* nasil luzumsuz bilgi */
- evcil[6]->yasi = 10; /* yazilabilecegini gosterir. */
-
- /* yukarda tanimladiklarimizi yazalim. */
-
- for (index = 0;index <12;index++) {
- point = evcil[index];
- printf("%s, bir %s, ve %d yasindadir.\n", point->ismi,
- point->cinsi, point->yasi);
- }
-
- /* Iyi programlama teknigi, dinamik yaratilmis sahanin, */
- /* sisteme iade edilmesini soyler.. */
-
- for (index = 0;index < 12;index++)
- free(evcil[index]);
- }
-
- ================================================================
-
- Bu program, bir oncekine cok benzer. Basit tutmak icin, 12 elemanlik bir
- pointer dizisi tanimliyoruz, ve bir "point" isimli bir pointer daha
- tanimliyoruz.
-
- Size yeni olan "*evcil[12]" terimini biraz anlatmakta fayda var. Burada
- yaptigimiz 12 tane pointer'dan olusan bir dizi tanimladik. Ilki "evcil[0]"
- ve sonuncusu "evcil[11]". Aslinda, bir diziyi indekssiz kullanmak, o
- dizinin adresini verdiginden, kendi basina "evcil" demekle, pointerin
- pointerini tanimlamis oluyoruz. Bu C de tumuyle yasaldir, ve hatta daha
- ileri de gidebilirsiniz - fakat cabucak kafaniz karisir. Dolayisi ile,
- "int ****pt" demek, yasaldir, ve bu bir pointer'in pointer'inin
- pointer'inin pointer'ini tanimlar - sayet dogru saydiysam. Iyice C ye
- alisincaya kadar bu tip seylerden kacinmanizi tavsiye ederim.
-
- Simdi, 12 tane pointer'imiz var, ve biz bunlar herhangi bir pointer gibi
- kullanabiliriz. Bir dongu icinde kendimize dinamik yer acip, icine
- istedigimiz verileri yazabiliriz. Rastgele secilmis bazi sahalara yeniden
- bilgi atadiktan sonra, ekrana sonuclari yaziyoruz. "point" isimli pointer,
- sadece size gosterme amaci ile kullanilmistir. Veri, "evcil[n]" diyerek
- tanimlanabilirdi. Son olarak 12 veri bloku "free" ile serbest birakilir ve
- program sona erer.
-